import json
import os

import dotenv
from attr.setters import convert
from langchain_community.tools import MoveFileTool
from langchain_core.messages import HumanMessage
from langchain_core.tools import tool, StructuredTool
from langchain_core.utils.function_calling import convert_to_openai_function
from langchain_openai import ChatOpenAI
from pydantic import Field, BaseModel


#使用@tools装饰器定义工具

@tool
def add_number_1(a:int , b:int) -> int:
    """
    计算两个整数的和
    Args:
        a (int): 第一个整数
        b (int): 第二个整数
    Returns:
        int: 两个整数的和
    """
    return a + b

print(f"name={add_number_1.name}") # 默认的名称为函数名
print(f"name={add_number_1.args}") # 默认的参数为函数的参数
print(f"name={add_number_1.description}") # 默认的描述为函数的注释
print(f"name={add_number_1.return_direct}") # 默认的返回值为False


#============================================================================


# 定义工具,使用属性覆盖默认值
@tool(name_or_callable="add_function" , description="计算两个整数的和" , return_direct=True)
def add_number_2(a:int , b:int) -> int:
    """
    计算两个整数的和
    Args:
        a (int): 第1个整数
        b (int): 第2个整数
    Returns:
        int: 2个整数的和
    """
    return a + b

print(f"name={add_number_2.name}") # 默认的名称为函数名
print(f"name={add_number_2.args}") # 默认的参数为函数的参数
print(f"name={add_number_2.description}") # 默认的描述为函数的注释
print(f"name={add_number_2.return_direct}") # 默认的返回值为False

# 调用工具
print(add_number_2.invoke({"a": 1, "b": 2}))

#==================================================================================
# 使用args_schema定义参数
class FiledInfo(BaseModel):
    a:int = Field(description="第1个整数")
    b:int = Field(description="第2个整数")

@tool(name_or_callable="add_function" , description="计算两个整数的和" , return_direct=True ,args_schema=FiledInfo)
def add_number_3(a:int , b:int) -> int:
    """
    计算两个整数的和
    Args:
        a (int): 第1个整数
        b (int): 第2个整数
    Returns:
        int: 2个整数的和
    """
    return a + b

print(f"name={add_number_3.args}") # 默认的参数为函数的参数

#===================================================================================
# StructuredTool  from_function()的使用

#声明一个函数
def search_google(query : str):
    return "google搜索结果"

class QueryInfo(BaseModel):
    query:str = Field(description="搜索的内容")

#定义工具
search_tool = StructuredTool.from_function(
    func=search_google
    , name="search_google"
    , description="使用google进行搜索,并将结果返回给用户"
    , args_schema=QueryInfo
    , return_direct=True  # 返回结果为直接结果,如果是FALSE则返回给AI由AI继续处理，默认为FALSE
)

print(f"name={search_tool.name}") # 默认的名称为函数名
print(f"args={search_tool.args}") # 默认的参数为函数的参数
print(f"description={search_tool.description}") # 默认的描述为函数的注释
print(f"return_direct={search_tool.return_direct}") # 默认的返回值为False

#==================================举例1==================================================
def fun_1():
    dotenv.load_dotenv()
    chat_model = ChatOpenAI(
        model=os.getenv("MODEL_NAME")
        , base_url=os.getenv("BASE_URL")
        , api_key=os.getenv("API_KEY")
        , temperature=0.8  # 精确度
        , max_tokens=1024  # 回答长度
    )

    # 创建工具实例
    move_tool = MoveFileTool()

    # 直接测试工具调用
    try:
        result = move_tool.invoke({
            "source_path": "F:/444.xls",
            "destination_path": "D:/444.xls"
        })
        print(f"文件移动成功: {result}")
    except Exception as e:
        print(f"文件移动失败: {e}")

    # 将工具放入列表中，然后转换为OpenAI函数
    tools = [move_tool]  # 将工具放入列表
    functions = [convert_to_openai_function(t) for t in tools]  # 现在正确遍历工具列表

    message = [HumanMessage(content="将文件移动到D盘")]

    response = chat_model.invoke(
        input=message,
        functions=functions
    )
    print(response)


#fun_1()

#==================================举例2==================================================

#声明一个函数
def search_weather(query : str):
    return "今日气温20摄氏度，南风4级，多云"

def fun_2():
    dotenv.load_dotenv()
    chat_model = ChatOpenAI(
        model=os.getenv("MODEL_NAME")
        , base_url=os.getenv("BASE_URL")
        , api_key=os.getenv("API_KEY")
        , temperature=0.8  # 精确度
        , max_tokens=1024  # 回答长度
    )

    # 创建工具实例1
    move_tool = MoveFileTool()

     # 创建工具实例2
    search_tool = StructuredTool.from_function(
        func=search_weather
        , name="search_weather"
        , description="查询今日天气,并将结果返回给用户"
        , return_direct=True
    )
    # 将工具放入列表中，然后转换为OpenAI函数
    tools = [search_tool,move_tool]  # 将工具放入列表
    functions = [convert_to_openai_function(t) for t in tools]  # 现在正确遍历工具列表

    message = [HumanMessage(content="把F:\\444.xls文件移动到D:\\")] #1.你好 ，2 查看天气，3 把F:\\444.xls文件移动到D:\\，4 退出

    response = chat_model.invoke(
        input=message,
        functions=functions
    )

    if "function_call" in response.additional_kwargs:
        tool_name = response.additional_kwargs["function_call"]["name"]
        tool_args = json.loads(response.additional_kwargs["function_call"]["arguments"])
        print(f"调用工具: {tool_name}, 参数: {tool_args}")
        if "search_weather" == tool_name:
            result = search_tool.run(tool_args)
            print(f"工具返回结果: {result}")
        if "move_file" == tool_name:
            result = move_tool.run(tool_args)
            print(f"工具返回结果: {result}")
    else:
        print(f"AI回答: {response.content}")

fun_2()